#ifndef _LINUX_IRQ_H
#define _LINUX_IRQ_H

#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>

#include <asm/thread_info.h>

#define NR_IRQS		10

struct irq_desc;
struct irq_data;

typedef	void (*irq_flow_handler_t)(struct irq_desc *desc);

struct irq_domain_ops {
	int (*match)(struct irq_domain *d, struct device_node *node,
		     enum irq_domain_bus_token bus_token);
	int (*select)(struct irq_domain *d, struct irq_fwspec *fwspec,
		      enum irq_domain_bus_token bus_token);
	int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);
	void (*unmap)(struct irq_domain *d, unsigned int virq);
	int (*xlate)(struct irq_domain *d, struct device_node *node,
		     const u32 *intspec, unsigned int intsize,
		     unsigned long *out_hwirq, unsigned int *out_type);
#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
	/* extended V2 interfaces to support hierarchy irq_domains */
	int (*alloc)(struct irq_domain *d, unsigned int virq,
		     unsigned int nr_irqs, void *arg);
	void (*free)(struct irq_domain *d, unsigned int virq,
		     unsigned int nr_irqs);
	int (*activate)(struct irq_domain *d, struct irq_data *irqd, bool reserve);
	void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
	int (*translate)(struct irq_domain *d, struct irq_fwspec *fwspec,
			 unsigned long *out_hwirq, unsigned int *out_type);
#endif
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
	void (*debug_show)(struct seq_file *m, struct irq_domain *d,
			   struct irq_data *irqd, int ind);
#endif
};

struct irq_domain {
	// struct list_head link;
	const char *name;
	const struct irq_domain_ops *ops;
	void *host_data;
	unsigned int flags;
	unsigned int mapcount;

	/* Optional data */
// 	struct fwnode_handle *fwnode;
// 	enum irq_domain_bus_token bus_token;
// 	struct irq_domain_chip_generic *gc;
// #ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
// 	struct irq_domain *parent;
// #endif

	/* reverse map data. The linear map gets appended to the irq_domain */
	irq_hw_number_t hwirq_max;
	unsigned int revmap_size;
	// struct radix_tree_root revmap_tree;
	// struct mutex revmap_mutex;
	struct irq_data *revmap[];
};

struct irq_chip {
	struct device	*parent_device;
	const char	*name;
	unsigned int	(*irq_startup)(struct irq_data *data);
	void		(*irq_shutdown)(struct irq_data *data);
	void		(*irq_enable)(struct irq_data *data);
	void		(*irq_disable)(struct irq_data *data);

	void		(*irq_ack)(struct irq_data *data);
	void		(*irq_mask)(struct irq_data *data);
	void		(*irq_mask_ack)(struct irq_data *data);
	void		(*irq_unmask)(struct irq_data *data);
	void		(*irq_eoi)(struct irq_data *data);

	int		(*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);
	int		(*irq_retrigger)(struct irq_data *data);
	int		(*irq_set_type)(struct irq_data *data, unsigned int flow_type);
	int		(*irq_set_wake)(struct irq_data *data, unsigned int on);

	void		(*irq_bus_lock)(struct irq_data *data);
	void		(*irq_bus_sync_unlock)(struct irq_data *data);

	void		(*irq_cpu_online)(struct irq_data *data);
	void		(*irq_cpu_offline)(struct irq_data *data);

	void		(*irq_suspend)(struct irq_data *data);
	void		(*irq_resume)(struct irq_data *data);
	void		(*irq_pm_shutdown)(struct irq_data *data);

	void		(*irq_calc_mask)(struct irq_data *data);

	void		(*irq_print_chip)(struct irq_data *data, struct seq_file *p);
	int		(*irq_request_resources)(struct irq_data *data);
	void		(*irq_release_resources)(struct irq_data *data);

	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

	int		(*irq_get_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool *state);
	int		(*irq_set_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool state);

	int		(*irq_set_vcpu_affinity)(struct irq_data *data, void *vcpu_info);

	void		(*ipi_send_single)(struct irq_data *data, unsigned int cpu);
	void		(*ipi_send_mask)(struct irq_data *data, const struct cpumask *dest);

	int		(*irq_nmi_setup)(struct irq_data *data);
	void		(*irq_nmi_teardown)(struct irq_data *data);

	unsigned long	flags;
};

struct irq_data {
	u32			mask;
	unsigned int		irq;
	unsigned long		hwirq;
	// struct irq_common_data	*common;
	struct irq_chip		*chip;
	struct irq_domain	*domain;
#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
	struct irq_data		*parent_data;
#endif
	void			*chip_data;
};

struct irq_desc {
	// struct irq_common_data	irq_common_data;
	struct irq_data		irq_data;
	// unsigned int __percpu	*kstat_irqs;
	irq_flow_handler_t	handle_irq;
	struct irqaction	*action;	/* IRQ action list */
// 	unsigned int		status_use_accessors;
// 	unsigned int		core_internal_state__do_not_mess_with_it;
// 	unsigned int		depth;		/* nested irq disables */
// 	unsigned int		wake_depth;	/* nested wake enables */
// 	unsigned int		tot_count;
// 	unsigned int		irq_count;	/* For detecting broken IRQs */
// 	unsigned long		last_unhandled;	/* Aging timer for unhandled count */
// 	unsigned int		irqs_unhandled;
// 	atomic_t		threads_handled;
// 	int			threads_handled_last;
// 	raw_spinlock_t		lock;
// 	struct cpumask		*percpu_enabled;
// 	const struct cpumask	*percpu_affinity;
// #ifdef CONFIG_SMP
// 	const struct cpumask	*affinity_hint;
// 	struct irq_affinity_notify *affinity_notify;
// #ifdef CONFIG_GENERIC_PENDING_IRQ
// 	cpumask_var_t		pending_mask;
// #endif
// #endif
// 	unsigned long		threads_oneshot;
// 	atomic_t		threads_active;
// 	wait_queue_head_t       wait_for_threads;
// #ifdef CONFIG_PM_SLEEP
// 	unsigned int		nr_actions;
// 	unsigned int		no_suspend_depth;
// 	unsigned int		cond_suspend_depth;
// 	unsigned int		force_resume_depth;
// #endif
// #ifdef CONFIG_PROC_FS
// 	struct proc_dir_entry	*dir;
// #endif
// #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
// 	struct dentry		*debugfs_file;
// 	const char		*dev_name;
// #endif
// #ifdef CONFIG_SPARSE_IRQ
// 	struct rcu_head		rcu;
// 	struct kobject		kobj;
// #endif
// 	struct mutex		request_mutex;
// 	int			parent_irq;
// 	struct module		*owner;
	const char		*name;
};

#define for_each_action_of_desc(desc, act)			\
	for (act = desc->action; act; act = act->next)

extern struct irq_desc irq_desc[NR_IRQS];

extern void handle_fasteoi_irq(struct irq_desc *desc);
extern void handle_bad_irq(struct irq_desc *desc);

extern struct irq_data *irq_get_irq_data(unsigned int irq);

int handle_domain_irq(struct irq_domain *domain,
		      unsigned int hwirq, struct pt_regs *regs);
irqreturn_t handle_irq_event(struct irq_desc *desc);

struct irq_domain *__irq_domain_add(unsigned int size,
				    irq_hw_number_t hwirq_max, int direct_max,
				    const struct irq_domain_ops *ops,
				    void *host_data);

extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
				irq_hw_number_t hwirq, struct irq_chip *chip,
				void *chip_data, irq_flow_handler_t handler,
				void *handler_data, const char *handler_name);

extern struct irq_desc *__irq_resolve_mapping(struct irq_domain *domain,
					      irq_hw_number_t hwirq,
					      unsigned int *irq);


static inline unsigned int irq_find_mapping(struct irq_domain *domain,
					    irq_hw_number_t hwirq)
{
	unsigned int irq;

	if (__irq_resolve_mapping(domain, hwirq, &irq))
		return irq;

	return 0;
}

static inline struct irq_desc *irq_resolve_mapping(struct irq_domain *domain,
						   irq_hw_number_t hwirq)
{
	return __irq_resolve_mapping(domain, hwirq, NULL);
}

static inline struct irq_desc *irq_data_to_desc(struct irq_data *data)
{
	// return container_of(data->common, struct irq_desc, irq_common_data);
	return container_of(data, struct irq_desc, irq_data);
}

// static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *fwnode,
// 					 unsigned int size,
// 					 const struct irq_domain_ops *ops,
// 					 void *host_data)
static inline struct irq_domain *irq_domain_create_linear(unsigned int size,
					 const struct irq_domain_ops *ops,
					 void *host_data)
{
	return __irq_domain_add(size, size, 0, ops, host_data);
}

#endif
